//
// EdgeCompute.cpp
/**
对EdgeCompute类的定义
Created by 江 裕诚 on 13-5-3.

This file is part of the Bitmap Detcet tools.

The Bitmap Detcet tools is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

The Bitmap Detcet tools is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with the Bitmap Detcet tools; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.


*/

#include "EdgeCompute.h"
#include <iostream>


bmp::EdgeCompute::EdgeCompute(BYTE** data, LONG width, LONG height)
{
	if (data==NULL || data == (BYTE**)0xcccccccc)
	{
		std::cerr<<"请先进行二值化处理，在执行图像分割!";
		exit(1);
	}
    count = 0;
    length = 0;
    this->width = width;
    this->height = height;
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            if (data[i][j] == 255)
            {
                bmp::Point p(i, j);
                points.push_back(p);
                length++;
            }
        }
    }

}

bmp::EdgeCompute::~EdgeCompute(void)
{
    points.clear();
    tagPoints.clear();
}

void bmp::EdgeCompute::setCount()
{
    do
    {
        compute();
    } while (!points.empty());
    denoise();
}

void bmp::EdgeCompute::compute()
{
    //获取points中的第一个元素，并从points中删除
    std::vector<bmp::Point>::iterator itr;
    //访问首顶点，并标记首顶点已被访问
    bmp::Point* head = new bmp::Point(points[0]);
    //itr = points.begin();
    //itr = points.erase(itr);
    points[0].setVisited();

    std::vector<bmp::Point> tmpPoints;
    //tmpPoints.push_back(*head);
    execute(head, tmpPoints);
    tagPoints.push_back(tmpPoints);

}

//利用广度优先搜索算法进行连接图的计算
void bmp::EdgeCompute::execute(bmp::Point* head, std::vector<bmp::Point> &tmpPoints)
{
    std::vector<bmp::Point>::iterator itr;

    std::list<bmp::Point> q;

    q.push_back(*head);

    while (!q.empty())
    {

        *head = q.front();
        q.pop_front();
        bmp::Point* w = getNeighbor(*head);
        while ( w != NULL)
        {
            if (! w->isVisited())
            {
                itr = std::find(points.begin(), points.end(), *w);
                bmp::Point* i = &*itr;
                i->setVisited();
                q.push_back(*i);
                w = getNeighbor(*w);
            }
        }
    }

    for (itr = points.begin(); itr != points.end(); )
    {
        bmp::Point tmp = *itr;
        if (tmp.isVisited())
        {
            tmpPoints.push_back(tmp);
            itr = points.erase(itr);
        }
        else
        {
            itr++;
        }
    }


    /*Point* tmp = head;

    Point* up = tmp->up();
    Point* down = tmp->down();
    Point* left = tmp->left();
    Point* right = tmp->right();
    Point* downAndLeft = tmp->downAndLeft();
    Point* downAndRight = tmp->downAndRight();
    Point* upAndLeft = tmp->upAndLeft();
    Point* upAndRight = tmp->downAndRight();
    itr = std::find(points.begin(), points.end(), *up);
    while (itr != points.end())
    {
        tmpPoints.push_back(*itr);
        itr = points.erase(itr);
        tmp = up;
        up = tmp->up();
        down = tmp->down();
        left = tmp->left();
        right = tmp->right();
        downAndLeft = tmp->downAndLeft();
        downAndRight = tmp->downAndRight();
        upAndLeft = tmp->upAndLeft();
        upAndRight = tmp->downAndRight();
    }*/


    /*Point* up = head->up();
    itr = std::find(points.begin(), points.end(), *up);
    if (itr != points.end())
    {
        tmpPoints.push_back(*itr);
        itr = points.erase(itr);
        execute(up, tmpPoints);
    }

    Point* down = head->down();
    itr = std::find(points.begin(), points.end(), *down);
    if (itr != points.end())
    {
        tmpPoints.push_back(*itr);
        itr = points.erase(itr);
        execute(down, tmpPoints);
    }

    Point* left = head->left();
    itr = std::find(points.begin(), points.end(), *left);
    if (itr != points.end())
    {
        tmpPoints.push_back(*itr);
        itr = points.erase(itr);
        execute(left, tmpPoints);
    }

    Point* right = head->right();
    itr = std::find(points.begin(), points.end(), *right);
    if (itr != points.end())
    {
        tmpPoints.push_back(*itr);
        itr = points.erase(itr);
        execute(right, tmpPoints);
    }

    Point* upAndRight = head->upAndRight();
    itr = std::find(points.begin(), points.end(), *upAndRight);
    if (itr != points.end())
    {
        tmpPoints.push_back(*itr);
        itr = points.erase(itr);
        execute(upAndRight, tmpPoints);
    }

    Point* upAndLeft = head->upAndLeft();
    itr = std::find(points.begin(), points.end(), *upAndLeft);
    if (itr != points.end())
    {
        tmpPoints.push_back(*itr);
        itr = points.erase(itr);
        execute(upAndLeft, tmpPoints);
    }

    Point* downAndRight = head->downAndRight();
    itr = std::find(points.begin(), points.end(), *downAndRight);
    if (itr != points.end())
    {
        tmpPoints.push_back(*itr);
        itr = points.erase(itr);
        execute(upAndRight, tmpPoints);
    }

    Point* downAndLeft = head->downAndLeft();
    itr = std::find(points.begin(), points.end(), *downAndLeft);
    if (itr != points.end())
    {
        tmpPoints.push_back(*itr);
        itr = points.erase(itr);
        execute(downAndLeft, tmpPoints);
    }*/

}

void bmp::EdgeCompute::denoise()
{
    std::vector< std::vector<bmp::Point> >::iterator itr;
    UINT avg = 0;
    for (itr = tagPoints.begin(); itr != tagPoints.end(); itr++)
    {
        avg += itr->size();
    }
    avg /= tagPoints.size();
    for (itr = tagPoints.begin(); itr != tagPoints.end();)
    {
        if (itr->size()*2 < avg)
        {
            itr = tagPoints.erase(itr);
        }
        else
        {
            itr++;
        }
    }
}

bmp::Point* bmp::EdgeCompute::getNeighbor(bmp::Point& p)
{
    std::vector<bmp::Point>::iterator itr;
    bmp::Point* p_neighbor = NULL;

    p_neighbor = p.up();
    itr = std::find(points.begin(), points.end(), *p_neighbor);
    if (itr != points.end())
    {
        p_neighbor = &*itr;
        if (!p_neighbor->isVisited())
        {
            return p_neighbor;
        }
    }
    p_neighbor = p.down();
    itr = std::find(points.begin(), points.end(), *p_neighbor);
    if (itr != points.end())
    {
        p_neighbor = &*itr;
        if (!p_neighbor->isVisited())
        {
            return p_neighbor;
        }
    }
    p_neighbor = p.upAndLeft();
    itr = std::find(points.begin(), points.end(), *p_neighbor);
    if (itr != points.end())
    {
        p_neighbor = &*itr;
        if (!p_neighbor->isVisited())
        {
            return p_neighbor;
        }
    }
    p_neighbor = p.upAndRight();
    itr = std::find(points.begin(), points.end(), *p_neighbor);
    if (itr != points.end())
    {
        p_neighbor = &*itr;
        if (!p_neighbor->isVisited())
        {
            return p_neighbor;
        }
    }
    p_neighbor = p.downAndLeft();
    itr = std::find(points.begin(), points.end(), *p_neighbor);
    if (itr != points.end())
    {
        p_neighbor = &*itr;
        if (!p_neighbor->isVisited())
        {
            return p_neighbor;
        }
    }
    p_neighbor = p.downAndRight();
    itr = std::find(points.begin(), points.end(), *p_neighbor);
    if (itr != points.end())
    {
        p_neighbor = &*itr;
        if (!p_neighbor->isVisited())
        {
            return p_neighbor;
        }
    }
    p_neighbor = p.left();
    itr = std::find(points.begin(), points.end(), *p_neighbor);
    if (itr != points.end())
    {
        p_neighbor = &*itr;
        if (!p_neighbor->isVisited())
        {
            return p_neighbor;
        }
    }
    p_neighbor = p.right();
    itr = std::find(points.begin(), points.end(), *p_neighbor);
    if (itr != points.end())
    {
        p_neighbor = &*itr;
        if (!p_neighbor->isVisited())
        {
            return p_neighbor;
        }
    }

    return NULL;
}

void bmp::EdgeCompute::print()
{
    for (std::vector<bmp::Point>::iterator itr = points.begin(); itr != points.end(); itr++)
    {
        std::cout<<*itr;
    }
}

int bmp::EdgeCompute::getCount()
{
    setCount();
    count = tagPoints.size();
    for (int i = 0; i < tagPoints.size(); i++)
    {
        bmp::Bitmap b(tagPoints[i], width, height, i);
        b.createNewBitmap();
    }
    return count;
}
